/*
 * @ Desc: 提供四方103有关的数据类型结构
 *
 * */

#ifndef SF103_TYPE_H
#define SF103_TYPE_H

#include <QByteArray>
#include <QList>
#include "utils.h"
//#include "IEC103Type.h"
#define TYP_POSI     0
#define VSQ_POSI     2
#define COT_POSI    4           // 传输原因，典型值  42（0x2A） 对通用分类读命令的有效数据响应， 0x2B 无效
#define ADDR_POSI    6
#define FUN_POSI     8
#define INF_POSI     10
#define RII_POSI     12
#define NGD_POSI     14       // 通用分类数据集数目，描述后面接了几个数据元
#define GIN_GROUP_POSI    16      // 根据定值模板来 选择条目组号
#define GIN_TNTRY_POSI    18
#define KOD_POSI    20          // 数据的类别描述，是实际值还是缺省值还是精度
#define GDD_DATA_TYPE_POSI   22      // 以上为固定的
#define GDD_DATA_SIZE_POSI   24
#define GDD_DATA_NUM_STA_POSI    26      //数目和后续状态
#define GID_POSI    28   // 通用分类标识数据 GID ，占用空间数据宽度* 数据


#define P103_STARTUP_V_CHAR			0x68	/* 可变帧启动字符 */
#define P103_STARTUP_S_CHAR			0x10	/* 固定帧启动字符 */
#define P103_STOPDOWN_CHAR			0x16	/* 通信帧结束字符 */
#define P103_MOD_15					0x7FFFU	/* 序号模值 */

// 四方 tcp 方式报文格式各个字段的下标位置
#define POS_START_1 0
#define POS_LEN_L 1
#define POS_LEN_H 2
#define POS_SRC_DEV_ADDR_L 3
#define POS_SRC_DEV_ADDR_H 4
#define POS_CTRL_0 5
#define POS_CTRL_1 6
#define POS_CTRL_2 7
#define POS_CTRL_3 8

//  ASDU

#define APCI_HEAD "90eb"
#define APCI_END "ffff"

#define KOD_REAL_VALUE     "01"    //描述类别  1为实际值                   设定的值
#define KOD_DEFAULT_VALU     "02"    //描述类别  2为缺省值                   默认定值
#define KOD_DIMENSION     "03"    //描述类别  值的量程范围，也就是最小值最大值
#define KOD_ACCURACY     "05"    //描述类别  数据准确度也就是步长
#define KOD_COFFE     "06"    //描述类别  因子
#define KOD_UNIT     "09"    //描述类别                            量纲 也就是单位
#define KOD_DESCRIPTER    "0a"    //描述类别                             描述（定值名字）


// U帧 传输未编号的控制命令功能 ， S 帧传输对站端的确认报文(编号的监视)， I帧传输信体(包含ASDU)
// 发送方每发送一个报文，发送序号加1， 接收方每收到一个和接受序号相等的报文接受序号加一
struct SF_APCI {
    QByteArray m_start = "68";
    QByteArray m_lenL;           // len = 6 + asdu 长度
    QByteArray m_lenH;           // 长度高字节
    QByteArray srcAddrL;         //源设备地址, 保护地址的最后两个字段，低字节在前
    QByteArray srcAddrH;         //源设备地址
    QByteArray m_ctrl0;         // 第一个控制域的最低比特位=0 定义 I 帧格式          发送序列号LSB  8位位组 ,控制域1 = TxCounter & 0xFE
    QByteArray m_ctrl1;         // 发送序列号 MSB, 控制域2 = (TxCounter >> 8) & 0xFF
    QByteArray m_ctrl2;         // 接收序列号 LSB        最低位=0, 控制域3 = RxCounter & 0xFE
    QByteArray m_ctrl3;         // 接收序列号 MSB, 控制域4 = (RxCounter >> 8) & 0xFF

    inline QByteArray getAPCI(uint16_t  srcAddrL, uint16_t srcAddrH)
    {
        QByteArray transFrame;
        QByteArray d1b =  Utils::unsignedToHexStr(srcAddrL);
        QByteArray d2b =  Utils::unsignedToHexStr(srcAddrH);

       // transFrame.resize(20);          // 传输层 APCI 占20个字节
        transFrame.push_back(m_start);
        transFrame.push_back(m_lenL);
        transFrame.push_back(m_lenH);
        transFrame.push_back(d2b);          // 场站地址
        transFrame.push_back(d1b);          // 源设备地址
        transFrame.push_back(m_ctrl0);
        transFrame.push_back(m_ctrl1);
        transFrame.push_back(m_ctrl2);
        transFrame.push_back(m_ctrl3);
        return transFrame;
    }
};


struct SF_OneDataSetItemStruct{
    QByteArray m_ginGroup;       // 1个字节 ， 组号
    QByteArray m_ginNo;          // 1个字节， 条目号
    QByteArray m_kod;            // kod ， 描述类别，名字，值，单位。。。
    QByteArray m_dataType;       // 数据类型
    QByteArray m_dataWidth;      // 数据宽度
    QByteArray m_dataNum;        // 数据数据数目，定值一般都是一个值
    QByteArray m_dataValue;  // 值
};

struct SF_ASDUStruct{
    QString m_serverType;   // 1.服务类型 ， service type = 15 主站发送， 0A ，
    QString m_vsq;          // 2.可变结构限定词
    QString m_cot;          // 3.传送原因
    QString m_addr;         // 4.应用服务单元地址
    QString m_fun;          // 5.功能类型
    QString m_inf;          // 6.信息号
    QString m_rii ;         // 7.由主站端提供，设备只管回一样的
    QString m_ngd;          // 8.数据集数目
    QList<SF_OneDataSetItemStruct> m_dataSetsList;    // 所有的需要传输的数据

    inline QString asduToQString()
    {
        QString packet;
        packet.append(this->m_serverType + this->m_vsq + this->m_cot + this->m_addr + this->m_fun + this->m_inf + this->m_rii + this->m_ngd);
        // dataSet 部分转 QString
        for(int i=0; i< m_dataSetsList.count(); i++)
        {
            packet.append(this->m_dataSetsList[i].m_ginGroup);
            packet.append(this->m_dataSetsList[i].m_ginNo);
            packet.append(this->m_dataSetsList[i].m_kod);
            packet.append(this->m_dataSetsList[i].m_dataType);
            packet.append(this->m_dataSetsList[i].m_dataWidth);
            packet.append(this->m_dataSetsList[i].m_dataValue);
        }
        return packet;
    }
};

// 主站向子站传输为控制方向

//103固定帧格式
struct SFUnChangeAbleFrame
{
    uint8_t startUpChar;    // 0x10
    uint8_t ctrl;
    uint8_t addr;
    uint8_t cs;
    uint8_t endChar;     // 0x16
    inline void createFrame( uint8_t i_ctrl, uint8_t i_addr );
};

inline void SFUnChangeAbleFrame::createFrame( uint8_t i_ctrl, uint8_t i_addr )
{
    startUpChar  = P103_STARTUP_S_CHAR;
    ctrl = i_ctrl;
    addr = i_addr;
    cs   = ctrl + addr;         // 校验和
    endChar  = P103_STOPDOWN_CHAR;
}

//103可变帧格式
class SFChangeableFrame
{
private:
    uchar startUpChar1 = 0x68;
    uchar len1;       // len = asdu 字节数 +  2
    uchar len2;
    uchar startUpChar2 = 0x68;
    uchar ctrl;       // 控制域
    uchar addr;       //链路地址
    QByteArray asdu;    //应用协议数据单元
    uchar checkCode;      // 校验码
    uchar endChar;        //结束符号

public:
    int getSize()
    {
        return sizeof(SFChangeableFrame)-1;
    }

    QByteArray getChangeableFrame()
    {
        QByteArray ret;
        ret.append(startUpChar1);
        ret.append(len1);
        ret.append(len2);
        ret.append(startUpChar2);
        ret.append(ctrl);
        ret.append(addr);
        ret.append(asdu);
        ret.append(checkCode);
        ret.append(endChar);

        return ret;
    }
};

//传输层报文结构 apci
class APCI_Frame_SF
{
public:
    uchar head1 = 0x68;
    uchar lenL =  0x00;        // len = lenH之后的部分长度之（包括asdu的长度,占用两个字节
    uchar lenH = 0x00;
    uchar srcDeviceAddrL = 0x00;     //源厂站地址, 跨厂站通讯，数据发送端
    uchar srcDeviceAddrH = 0x00;     //源设备地址

    uchar ctrl0 = 0x00;            //数据编号,这个需要自增1，否则一次连接智能发送一次同一个数据
    uchar ctrl1 = 0x00;        //设备类型
    uchar ctrl2 = 0x00;   // 设备网络状态
    uchar ctrl3 = 0x00;   // 首层路由地址

    //90eb 14000000 90eb 0 23000 dc000 2b00 5000 0000 ffff
    inline QByteArray getAPCI(uchar  srcDeviceAddr, uchar srcDeviceAddr1)
    {
        QByteArray transFrame;
       // transFrame.resize(20);          // 传输层 APCI 占20个字节
        transFrame.push_back(head1);
        transFrame.push_back(lenL);
        transFrame.push_back(lenH);
        transFrame.push_back(srcDeviceAddr);
        transFrame.push_back(srcDeviceAddr1);

        transFrame.push_back(ctrl0);
        transFrame.push_back(ctrl1);
        transFrame.push_back(ctrl2);
        transFrame.push_back(ctrl3);       // 数据编号，在应用的时候累
        return transFrame;
    }
};


//传输层报文结构 apci , v1版本， udp 版
class SF_APCI_Frame_1
{
public:
    //90eb 14000000 90eb 0 23000 dc000 2b00 5000 0000 ffff
    inline QByteArray getAPCI(uchar  srcDeviceAddr)
    {
        QByteArray transFrame;
       // transFrame.resize(20);          // 传输层 APCI 占20个字节
        transFrame.push_back(head0);
        transFrame.push_back(len0);
        transFrame.push_back(len1);
        transFrame.push_back(head1);
        transFrame.push_back(ctrlC);
        transFrame.push_back(srcDeviceAddr);

        transFrame.push_back(cs);
        return transFrame;
    }

    QByteArray head0 = "68";
    QByteArray len0 = "00";        // len 包括控制域、地址域、链路用户数据的8位位组个数
    QByteArray len1 = "00";        // 长度重复
    QByteArray head1 = "68";
    QByteArray ctrlC = "00";      //数据编号,这个需要自增1，否则一次连接智能发送一次同一个数据
    QByteArray AddrA = "00";       //设备类型
    SF_ASDUStruct asdu;
    QByteArray cs;               // 校验和
    QByteArray endChar = "16";
};


class SF_APCI_Frame
{
public:
    QByteArray head1 = "90eb";
    QByteArray  len =  "14000000";        // len = head2 之后的部分长度之和 20 + asdu的长度,占用两个字节
    QByteArray head2 = "90eb";
    QByteArray srcFactorAddr = "0000";     //源厂站地址, 跨厂站通讯，数据发送端
    QByteArray srcDeviceAddr;     //源设备地址
    QByteArray destFactoryAddr = "0000";   //目标厂站地址，数据接收厂站地址
    QByteArray destDeviceAddr;    //目标设备地址
    QByteArray dataNo = "0000";            //数据编号,这个需要自增1，否则一次连接智能发送一次同一个数据
    QByteArray deviceType = "2b00";        //设备类型
    QByteArray deviceNetState = "5000";   // 设备网络状态
    QByteArray firstRuteDeviceAddr = "0000";   // 首层路由地址
    QByteArray lastRuteDeviceAddr = "0000";    // 最后设备地址
    QByteArray reseverByte = "ffff";       //保留字节
    //90eb 14000000 90eb 0 23000 dc000 2b00 5000 0000 ffff
    inline QByteArray getAPCI(uint16_t  srcDevAddr, uint16_t destDevAddr)
    {
        QByteArray transFrame;

        QByteArray d1b =  Utils::unsignedToHexStr(srcDevAddr);
        QByteArray d2b =  Utils::unsignedToHexStr(destDevAddr);

       // transFrame.resize(20);          // 传输层 APCI 占20个字节
        transFrame.push_back(head1);
        transFrame.push_back(len);
        transFrame.push_back(head2);
        transFrame.push_back(srcFactorAddr);
        transFrame.push_back(d1b);
        transFrame.push_back(destFactoryAddr);
        transFrame.push_back(d2b);
        transFrame.push_back(dataNo);
        transFrame.push_back(deviceType);
        transFrame.push_back(deviceNetState);
        transFrame.push_back(firstRuteDeviceAddr);       // 数据编号，在应用的时候累加
        transFrame.push_back(lastRuteDeviceAddr);
        transFrame.push_back(reseverByte);
        return transFrame;
    }
};

// 一个定值组一个  BillTableStruct ，对应界面显示数据
struct SF_BillTableStruct{
    QString groupNo;    // 组号
    QString groupName;  // 组名
     // 组具体条目各项信息
    QStringList billNameList;
    QStringList billRealValueList;
    QStringList billDefaultValueList;
    QStringList billUnitList;
    QStringList billMinList;
    QStringList billMaxList;
    QStringList billStepsList;
    QStringList billTypeList;
};

enum SF_REPLY_TYPE
{
    REPLY_READ_YB_SF = -2,
    REPLY_READ_SETTINGS_AREA_SF,
    REPLY_TYPE_ALL_GROUP_TITLE_SF,
    REPLY_READ_SETTINGS_NAME_SF,
    REPLY_READ_SETTINGS_CURRVALUE_SF,
    REPLY_READ_DEFAULTVALUE_SF,
    REPLY_READ_SETTINGS_MIN_SF,
    REPLY_READ_SETTINGS_MAX_SF,
    REPLY_READ_SETTINGS_STEP_SF,
    REPLY_READ_SETTINGS_UNIT_SF,
    REPLY_READ_SETTINGS_DATA_TYPE_SF
};

enum SF_ASDU_TYPE
{
    ASDU_1_SF = 0x01,
    ASDU_2_SF = 0x02,
    ASDU_10_SF = 0x0A,         // 通用分类服务数据报文，在主站发送读取定值的时候子站回该类报文传数据
    ASDU_21_SF = 0x15,     // 通用分类服务命令，主站发读取定值
    ASDU_40_SF = 0x28,
    ASDU_41_SF = 0x29,
    ASDU_42_SF = 0x2A,
    ASDU_43_SF = 0x2B,
    ASDU_44_SF = 0x2C,
    ASDU_45_SF = 0x2D,
    ASDU_46_SF = 0x2E,
    ASDU_50_SF = 0x32,
};

#define TYPE_ASDU_OK_APPLY "0a"
#define TYPE_ASDU_NG_APPLY "2b"
#define TYPE_ASDU_ASK "15"

#define COT_S2C_TIMESTAMP_STR     "08"      //时间同步
#define COT_S2C_GETALL_START_STR  "09"      //总查询(总召唤)的启动
#define COT_S2C_COMMON_ORDER_STR  "14"   //一般命令
#define COT_S2C_GENERAL_WRITE_STR "28"   //通用分类写命令
#define COT_S2C_GENERAL_READ_STR  "2a"   //通用分类读命令
#define COT_S2C_CIRCLE_SEND_STR "02"

//FUN定义
#define FUN_GLB "ff"       //全局功能类型 ASDU 主：6,7,20,24,25, 从：5,23,26,27,28,29,30,31
#define FUN_GEN "fe"       //通用分类服务功能类型 ASDU主:10,21； 从：10

//INF（信息序号）定义
//#define INF_RESET_ORDER   0x13  //复归命令，所有装置相同
//#define INF_READ_GROUP    0xF1  //读一个组的全部条目的值或者属性 INF=241, ASDU=21
//#define INF_READ_EBTRY    0xF4  //读一个条目的值或者属性，单项定值的读取 INF=244, ASDU=21
//#define INF_CONFIRM_WRITE 0xF9  //带确认的写条目，定值下发时使用   INF=249, ASDU=10
//#define INF_EXEC_WRITE    0xFA  //带执行的写条目，定值固化时采用   INF=250, ASDU=10

#define INF_RESET_ORDER   "13"  //复归命令，所有装置相同
#define INF_READ_TITLE   "f0"
#define INF_READ_GROUP    "f1"  //读一个组的全部条目的值或者属性 INF=241, ASDU=21
#define INF_READ_EBTRY    "f4"  //读一个条目的值或者属性，单项定值的读取 INF=244, ASDU=21
#define INF_CONFIRM_WRITE "f9"  //带确认的写条目，定值下发时使用   INF=249, ASDU=10
#define INF_EXEC_WRITE    "fA"  //带执行的写条目，定值固化时采用   INF=250, ASDU=10

// 数据类型定义
#define DATA_TYPE_INT 0x04
#define DATA_ASCII_8 0X01
#define DATA_TYPE_BOOL 0X02
#define DATA_TYPE_UINT 0X03
#define DATA_TYPE_INT   0x04
#define DATA_TYPE_FLOAT 0X06
#define DATA_TYPE_SHORT_NUM 0X07
#define MAX_SIZE 1024
#endif // SF103_TYPE_H
